import {info, clear} from '../logview/index.js'
import _ from "lodash"
import api from "../../request/apis.js"
import {mapping} from "./RegisterJobTitleMapping.js";
import moment from "moment/moment.js";
import {mapping as shiftMapping} from "./RegisterShiftMapping.js"
import {toInt} from "../../utils/index.js";


const excludeDeptIds = ["786"];

const excludeDoctorIds = ['急诊核医学号', '发热门诊号', '急诊外科号', '急诊内科免费号',
    '急诊妇产科免费号', '急诊妇产科号', '急诊内科号', '急诊外科免费号', '机关便民门诊号', '急诊儿科免费号', '急诊儿科号', '急诊神经科免费号', '急诊神经科号',
    '急诊耳鼻喉科号', '急诊眼科号', '急诊口腔颌面外科号', '急诊皮肤科号', '急诊骨胸免费号', '急诊骨胸科号', '急诊骨科免费号', '急诊骨科号', '急诊96999', '急诊号',
    '急诊脑外科号', '急诊小儿外科号', '急诊ICU号', '急诊ICU免费号', '急诊高压氧科号', '妇科急诊号', '急诊分娩室号', '急诊分娩室免费号'];

const specExcludeDoctorIds = [];

export const locSync = async (d) => {
    console.log("要同步的数据为", d);
    // console.log(info)
    info(`一共有${d.length}条`);

    let syncList = JSON.parse(JSON.stringify(d));

    syncList = locDoctorExclude(syncList);

    if (!syncList || syncList.length <= 0) {
        info(`数据排除后，没有需要同步的，直接返回了`);
        return;
    }
    await setNewLoc(syncList);

    replaceDoctorInfo(syncList);

    await setNewDoctor(syncList);

    //科室需要分组然后处理
    let locMap = _.groupBy(syncList, (index) => {
        return index.locId;
    });

    //先根据科室分组
    await locMapSync(locMap);
}

const locDoctorExclude = (syncList) => {
    //需要过滤数据
    syncList = syncList.filter(item => {
        let filters = excludeDoctorIds.filter(excludeDoctorId => {
            if (excludeDoctorId + "" == item.userId + "") {
                info(`科室【${item.locName}】排除医生【${item.userName}】`);
                return true;
            }
            return false;
        });

        //如果有排除的医生ID
        if (filters.length > 0) {
            return false;
        }

        filters = specExcludeDoctorIds.filter(excludeDoctorId => {
            if (excludeDoctorId + "" == item.userId + "") {
                info(`科室【${item.locName}】排除医生【${item.userName}】`);
                return true;
            }
            return false;
        });

        //如果有排除的医生ID
        if (filters.length > 0) {
            return false;
        }

        // if(excludeDeptIds&&excludeDeptIds.length>0){
        filters = excludeDeptIds.filter(excludeDeptId => {
            if (excludeDeptId + "" == item.locId + "") {
                info(`科室【${item.locName}】排除,不同步`);
                return true;
            }
            return false;
        });
        // }
        //如果有排除的医生ID
        if (filters.length > 0) {
            return false;
        }
        return true;
    });
    return syncList;
}

const locMapSync = async (locMap) => {

    let index = 1;
    const length = size(locMap);
    // console.log(locMap)
    for (const key in locMap) {
        let dataArray = locMap[key];
        const locName = dataArray[0]?.locName;

        info(`现在开始同步科室【${locName}】配置 (${index}/${length})`);
        await deptSetting(locName, dataArray);
        info(`科室【${locName}】同步配置结束`);

        info(`科室【${locName}】现在根据排班医生分组`);

        //需要过滤数据
        dataArray = dataArray.filter(item => {
            const filters = excludeDoctorIds.filter(excludeDoctorId => {
                if (excludeDoctorId + "" == item.userId + "") {
                    info(`科室【${locName}】排除医生【${item.userName}】`);
                    return true;
                }
                return false;
            });
            //如果有排除的医生ID
            if (filters.length > 0) {
                return false;
            }
            return true;
        });

        if (dataArray.length <= 0) {
            info(`科室【${locName}】排除逻辑后，没有找到要同步的排班数据`);
            continue;
        }

        let docMap = _.groupBy(dataArray, (index) => {
            return index.userId;
        });

        await docMapSync(key, locName, docMap);
        info(`科室【${locName}】同步完成`);
        //同步完了后现在要进行提交了
        api.clearCache();
        info(`科室【${locName}】清除缓存完成`);

        info(`科室【${locName}】现在开始生成排班`);
        await submitSchedule(key, locName, dataArray[0]?.serviceDate);
        info(`科室【${locName}】生成结束 (${index}/${length})`);
        index++;
    }
}


const setNewLoc = async (dataArray) => {

    let locIdList = [];
    let locNameList = [];
    for (let i in dataArray) {
        const locId = dataArray[i].locId;
        locIdList.push(locId);
        locNameList.push(dataArray[i].locName)
    }
    const deptList = await api.deptSearch([
        {
            "attrCode": "out_code",
            "attrValues": locIdList
        }
    ]);

    if (!deptList || deptList.length <= 0) {
        info(`获取科室信息失败,不同步 ${locIdList},${locNameList}`)
        throw "获取科室信息失败";
    }

    for (let i in dataArray) {
        const userInfo = dataArray[i];

        const filters = deptList.filter(staff => {
            return staff.attrMap?.out_code == userInfo.locId;
        });

        if (!filters || filters.length <= 0) {
            info(`科室[${userInfo.locName}]【${userInfo.locId}获取信息失败,中断同步`)
            throw "获取科室信息失败";
        }
        userInfo.locId = filters[0].id + "";
    }
}

const setNewDoctor = async (dataArray) => {

    let userIdList = [];
    let userNameList = [];
    for (let i in dataArray) {
        const userId = dataArray[i].userId;
        userIdList.push(userId);
        userNameList.push(dataArray[i].userName);
    }
    const staffList = await api.staffSearch([
        {
            "attrCode": "oldSystemUserCode",
            "attrValues": userIdList
        }
    ]);
    if (!staffList || staffList.length <= 0) {
        info(`获取员工信息失败,不同步,${userIdList},${userNameList}`)
        throw "获取员工信息失败";
    }

    for (let i in dataArray) {
        const userInfo = dataArray[i];

        const filters = staffList.filter(staff => {
            return staff.attrMap?.oldSystemUserCode == userInfo.userId;
        });

        if (!filters || filters.length <= 0) {
            info(`员工[${userInfo.userName}]【${userInfo.userId}获取信息失败,中断同步`)
            throw "获取员工信息失败";
        }
        userInfo.userId = filters[0].id + "";
    }
}


export const locAppointmentSync = async (d, keywords) => {

    let syncList = JSON.parse(JSON.stringify(d));

    syncList = locDoctorExclude(syncList);


    if (!syncList || syncList.length <= 0) {
        info(`数据排除后，没有需要同步的，直接返回了`);
        return;
    }

    await setNewLoc(syncList);

    // await setNewDoctor(syncList);

    //科室需要分组然后处理
    let locMap = _.groupBy(syncList, (index) => {
        return index.locId;
    });

    info(`开始同步预约记录。`);
    let i = 0;
    for (const key in locMap) {
        const dataArray = locMap[key];
        const locName = dataArray[0]?.locName;
        const serviceDate = dataArray[0]?.serviceDate;

        if (i >= 1) {
            info(`科室【${locName}】整出多条来了，可能有点问题，需要关注。`);
        }
        //includeDoctorIds
        info(`科室【${locName}】同步预约记录开始`);
        await appointmentSync(key, locName, serviceDate, keywords);
        info(`科室【${locName}】同步预约记录成功`);
        i++;
    }
}

const appointmentSync = async (locId, locName, serviceDate, keywords) => {
    try {
        const syncResult = await api.appointmentSync(locId, serviceDate, keywords);
        // info(`${syncResult}`);
    } catch (e) {
        info(`执行超时了，继续下一次,${e}`);
    }

    //  await startSyncLog(tid);
}
const startSyncLog = (tid) => {
    const p = new Promise(async (resolve, reject) => {
        await repeatQueryLog(tid, 0, resolve);
    })
    return p;
}
const repeatQueryLog = async (tid, index, resolve) => {
    let result = null;
    try {
        result = await api.querySyncLog(tid);
    } catch (e) {
        resolve();
    }
    //如果包含处理完成
    if (result.indexOf("预约记录割接同步完成") != -1 || result.indexOf("没有获取到预约数据") != -1) {
        resolve();
        return;
    }
    if (result) {
        info(result);
        index = 0;
    } else {
        index++;
    }
    if (index > 20) {
        resolve();
        return;
    }
    setTimeout(function () {
        repeatQueryLog(tid, index, resolve);
    }, 1000);

}

const submitSchedule = async (locId, locName, serviceDate) => {
    const validateRangeDate = getWeekBeginEnd(new Date(`${serviceDate} 00:00:00`));

    let scheduleList = await api.listSchedule(locId, validateRangeDate.end, validateRangeDate.start);

    if (!scheduleList || scheduleList.length <= 0) {
        return;
    }


    const ruleIds = findPlainIds(scheduleList, serviceDate);
    if (!ruleIds || ruleIds.length <= 0) {
        info(`科室【${locName}】没有找到需要生成排班的数据`);
        // return;
    } else {
        //去一把重
        let newRuleIds = Array.from(new Set(ruleIds));
        //现在开始提交一把了
        try {
            await api.submitSchedule(newRuleIds);
        } catch (e) {
            info(`科室【${locName}】排班生成失败, ${e}`);
            throw e;
        }
        info(`科室【${locName}】排班生成完成`);
    }

    //提交完了在查询一次
    api.clearCache();

    info(`科室【${locName}】再次清除缓存完成`);

    scheduleList = await api.listSchedule(locId, validateRangeDate.end, validateRangeDate.start);

    const scheduleRuleIds = findRuleIds(scheduleList, serviceDate);
    if (!scheduleRuleIds || scheduleRuleIds.length <= 0) {
        info(`科室【${locName}】没有找到需要生成号源的数据`);
    } else {
        let newScheduleRuleIds = Array.from(new Set(scheduleRuleIds));

        for (const key in newScheduleRuleIds) {
            const scheduleRuleId = newScheduleRuleIds[key];
            //提交完了就要生成号源
            try {
                await api.submitGenerate(scheduleRuleId);
                info(`科室【${locName}】 【${scheduleRuleId}】生成号源成功`);
            } catch (e) {
                info(`科室【${locName}】${scheduleRuleId} ${serviceDate}生成号源报错了 ${e}`);
            }
        }
    }

}

const findRuleIds = (scheduleList, serviceDate) => {
    const ruleIds = [];
    //找到所有已保存的
    for (const key in scheduleList) {
        const schedule = scheduleList[key];

        const schedulePlanVOList = schedule.schedulePlanVOList;

        if (!schedulePlanVOList || schedulePlanVOList.length <= 0) {
            continue;
        }

        for (const cKey in schedulePlanVOList) {
            const schedulePlanVO = schedulePlanVOList[cKey];
            if (schedulePlanVO.planStatus == 2 && schedulePlanVO.serviceDate == serviceDate && !schedulePlanVO?.hadGeneralResource) {
                ruleIds.push(schedulePlanVO.relateRuleId);
            }
        }
    }
    return ruleIds;
}
const findPlainIds = (scheduleList, serviceDate) => {
    const ruleIds = [];
    //找到所有已保存的
    for (const key in scheduleList) {
        const schedule = scheduleList[key];

        const schedulePlanVOList = schedule.schedulePlanVOList;

        if (!schedulePlanVOList || schedulePlanVOList.length <= 0) {
            continue;
        }

        for (const cKey in schedulePlanVOList) {
            const schedulePlanVO = schedulePlanVOList[cKey];
            if (schedulePlanVO.planStatus == 1 && schedulePlanVO.serviceDate == serviceDate) {
                ruleIds.push(schedulePlanVO.id);
            }
        }
    }
    return ruleIds;
}
const deptSetting = async (deptName, dataArray) => {
    var locId = dataArray[0]?.locId;

    if (!locId) {
        return;
    }

    info(`科室【${deptName}】同步配置，获取配置信息`);
    //先查询
    const deptConfig = await api.getScheduleDeptConfigDetail(locId);

    if (!deptConfig) {
        info(`科室【${deptName}】同步配置，没有获取到配置信息，走新增配置`);
        //走新增
        //需要过滤数据
        let filterDataList = dataArray.filter(item => {
            return item.trLength != null;
        });

        let trLength = 5;
        if (filterDataList && filterDataList.length > 0) {
            trLength = filterDataList[0].trLength;
        }

        await addDeptConfig(locId, trLength);
        info(`科室【${deptName}】同步配置，没有获取到配置信息，新增配置结束`);
    } else {
        //不管
        info(`科室【${deptName}】同步配置，获取到了配置信息，所以不处理`);
    }
}

const addDeptConfig = async (locId, trLength) => {
    //需要计算时段长度
    const saveJson = {
        "deptId": locId,//科室名称
        "overtimeExpire": 0,//过时限制 是否可以过时取号
        "scheduleInterval": trLength || 5,//时段长度
        "registrationExpirationDays": 1,//复诊有效时间 todo 需要确认下
        "gender": "",//性别限制 不限
        "ageMinLimit": 0,//年龄限制
        "ageMaxLimit": 100,//年龄限制
        "ageUnit": "YEAR",//年龄限制
        "campusId": "30001002",//院区
        "orgId": "20001001"//机构
    }
    //保存
    await api.saveDeptConfig(saveJson);
}


const docMapSync = async (deptId, deptName, docMap) => {
    if (!docMap) {
        info(`科室【${deptName}】没有医生排班数据，直接返回了`);
        return;
    }
    let index = 1;
    const length = size(docMap);

    for (const key in docMap) {
        let dataArray = docMap[key];
        const doctorName = dataArray[0]?.userName;
        info(`科室【${deptName}】医生【${doctorName}】开始同步 (${index}/${length})`);

        //这里需要进行合并
        dataArray = docMerge(dataArray);
        for (const e in dataArray) {
            await docSync(deptId, deptName, key, doctorName, dataArray[e]);
        }
        info(`科室【${deptName}】医生【${doctorName}】同步结束 (${index}/${length})`);
        index++;
    }

}

const size = (map) => {

    if (!map) {
        return 0;
    }

    let i = 0;

    for (const key in map) {
        i++;
    }

    return i;

}

const replaceDoctorInfo = (dataArray) => {
    //先设置替诊医生
    for (const e in dataArray) {
        const data = dataArray[e];
        if (data.replaceDoctorId) {
            info(`科室【${data.locName}】医生【${data.userName}】发生了替诊，替诊医生ID为${data.replaceDoctorId}`);
            data.userId = data.replaceDoctorId + "";
        }
    }
}

const docMerge = (dataArray) => {
    let result = [];
    //现在开始合并，如果日期+班次+医生一致则要进行合并
    for (const e in dataArray) {
        const data = dataArray[e];
        const matchData = hasMatchDocMergeCondition(result, data);
        if (matchData) {
            info(`科室【${matchData.locName}】医生【${matchData.userName}】发生了合并`);
            matchData.load = toInt(matchData.load || 0) + toInt(data.load || 0);
            matchData.appLoad = toInt(matchData.appLoad || 0) + toInt(data.appLoad || 0);
            matchData.addLoad = toInt(matchData.addLoad || 0) + toInt(data.addLoad || 0);
            matchData.noApptSession = toInt(matchData.noApptSession || 0) + toInt(data.noApptSession || 0);
            matchData.numberOfRegisteredMail = toInt(matchData.numberOfRegisteredMail || 0) + toInt(data.numberOfRegisteredMail || 0);
            matchData.trRegNum = toInt(matchData.trRegNum || 0) + toInt(data.trRegNum || 0);
        } else {
            result.push(data);
        }
    }

    return result;
}

const hasMatchDocMergeCondition = (result, data) => {
    if (!result || result.length <= 0) {
        return null;
    }
    //如果日期+班次+医生一致则要进行合并
    let matchObj = null;
    for (let resultKey in result) {
        const resultObj = result[resultKey];

        if (resultObj.userId + "" == data.userId + "" && data.shiftId + "" == resultObj.shiftId + "" && data.serviceDate + "" == resultObj.serviceDate + "") {
            matchObj = resultObj;
            break;
        }
    }
    return matchObj;
}


const docSync = async (deptId, deptName, docId, docName, data) => {
    //现在开始新增排班
    await saveScheduleConfig(data);

}

const saveScheduleConfig = async (data) => {
    const serviceDateStr = data.serviceDate;
    if (!serviceDateStr) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，找不到服务日期直接返回了`);
        throw "同步失败";
    }

    const week = weekCheck(new Date(`${serviceDateStr} 00:00:00`));
    if (!week) {
        info(`科室【${data.locName}】医生【${data.userName}】【${serviceDateStr}】同步失败，获取星期失败`);
        throw "同步失败";
    }

    const validateRangeDate = getWeekBeginEnd(new Date(`${serviceDateStr} 00:00:00`));
    //判断是否已经同步过了
    const hasSaveFlag = await hasSave(validateRangeDate, data);
    if (hasSaveFlag) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，已经有数据了`);
        return;
    }

    let locationId = await findLocation(data.locId);

    if (!locationId) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，获取不到关联的诊区`);
        throw "同步失败";
    }

    if (!data.sessId) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，老系统的挂号职称为空`);
        throw "同步失败";
    }

    //挂号类别对照
    const mp = mapping[data.sessId];
    if (!mp) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，找不到医生映射的服务项目[${data.sessDesc}]`);
        throw "同步失败";
    }

    if (!mp.serviceItemCategory || !mp.serviceItemId) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，找不到医生映射的服务项目-[${data.sessDesc}]`);
        throw "同步失败";
    }

    const numLimit = data.noApptSession && data.noApptSession != 0 && data.noApptSession != '0' ? data.noApptSession : data.appLoad && data.appLoad != 0 && data.appLoad != '0' ? data.appLoad : data.numberOfRegisteredMail;
    if (!numLimit) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，预约限额找不到`);
        throw "同步失败";
    }
    const shiftMpInfo = await shiftSeassonInfo(data.shiftId);
    if (!shiftMpInfo) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，获取班次映射信息失败`);
        throw "同步失败";
    }
    if (!shiftMpInfo.shiftId) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，获取班次映射信息新系统班次ID失败`);
        throw "同步失败";
    }
    if (!shiftMpInfo.shiftSeasonId) {
        info(`科室【${data.locName}】医生【${data.userName}】同步失败，获取班次映射信息新系统shiftSeasonId失败`);
        throw "同步失败";
    }


    const saveJson = {
        "deptId": data.locId,//科室
        "providerId": data.userId,//医生
        "locationId": locationId,//地址-诊区
        "serviceItemCategory": mp.serviceItemCategory,//挂号类别
        "serviceItemId": mp.serviceItemId,//挂号级别
        "numExtraLimit": parseInt(data.addLoad || 0),//加号限额
        "numLimit": parseInt(numLimit),//号源数
        "frequencyValues": [//星期几
            week], "shiftId": shiftMpInfo.shiftId,//班次ID
        "validDate": validateRangeDate.start,//一周开始时间
        "expireDate": validateRangeDate.end,//一周结束时间
        "shiftSeasonList": [//班次时令
            {
                "beginTime": getHours(data.trStartTime),//开始时间
                "endTime": getHours(data.trEndTIme),//结束时间
                "shiftSeasonId": shiftMpInfo.shiftSeasonId//排次时令id
            }]
    };
    await api.saveSchedule(saveJson);
}

const hasSave = async (validateRangeDate, data) => {
    const scheduleList = await api.listSchedule(data.locId, validateRangeDate.end, validateRangeDate.start);

    if (!scheduleList) {
        return false;
    }

    let shiftMpInfo = await shiftSeassonInfo(data.shiftId);
    if (!shiftMpInfo) {
        shiftMpInfo = {}
    }
    const week = weekCheck(new Date(`${data.serviceDate} 00:00:00`));

    let result = false;
    for (const key in scheduleList) {
        const schedule = scheduleList[key];

        const schedulePlanVOList = schedule.schedulePlanVOList;
        if (!schedulePlanVOList || schedulePlanVOList.length <= 0) {
            continue
        }
        //班次匹配上了
        if (schedule.shiftId == shiftMpInfo.shiftId && schedule.providerId == data.userId) {
            //还要匹配星期
            for (const cKey in schedulePlanVOList) {
                const schedulePlanVO = schedulePlanVOList[cKey];

                if (schedulePlanVO.shiftId == shiftMpInfo.shiftId && schedulePlanVO.frequencyValue == week + "" && schedulePlanVO.providerId == data.userId) {
                    result = true;
                    break;
                }
            }
        }
    }
    return result;
}


const getHours = (dateTime) => {
    const date = moment(new Date()).format('YYYY-MM-DD');
    const dateStr = date + " " + dateTime;
    return moment(new Date(dateStr)).format('HH:mm');
}
const shiftSeassonInfo = async (shiftId) => {
    const shiftMpInfo = shiftMapping[shiftId];
    if (!shiftMpInfo) {
        return;
    }
    // shiftMpInfo.shiftId;
    const shiftList = await api.getShiftList();
    if (!shiftList) {
        return;
    }
    let result = null;
    for (const key in shiftList) {
        const shift = shiftList[key];
        if (shift.shiftId == shiftMpInfo.shiftId) {
            result = shift;
            break;
        }
    }
    if (!result) {
        return null;
    }

    return {
        shiftId: result.shiftId, shiftSeasonId: result.shiftSeasons[0]?.shiftSeasonId
    }
}

const findLocation = async (deptId) => {

    //诊区估计需要取第一条哦
    const locations = await api.listLocation(deptId);
    if (!locations) {
        return null;
    }
    let locationId = null;
    if (locations?.defaultLocationIds?.length > 0) {
        locationId = locations?.defaultLocationIds[0];
    } else if (locations?.locationTree?.length > 0) {
        locationId = locations?.locationTree[0]?.value;
    }
    return locationId;

}


const getWeekBeginEnd = (date) => {
    var s = weekCheck(date);

    const start = moment(date).subtract(s - 1, 'days').format('YYYY-MM-DD');
    const end = moment(date).add(7 - s, 'days').format('YYYY-MM-DD');
    return {
        start, end
    };
}

const weekCheck = (date) => {
    let s = moment(date).format("E");
    return s;
}